import { chunk, shuffle, sortBy, groupBy, values, keys } from 'lodash'
import EventEmitter from './class/EventEmitter'
import { watch } from 'vue'
import store from 'store'
import { io } from 'socket.io-client'
export default class Poker {
  constructor(options) {
    this.context = options.context
    this.wsUrl = 'ws://192.168.11.207:3000'
    this.nowUser = 0
    this.userNum = 3
    this.nowCard = null
    this.history = []
    this.my = store.get('pokerMy') || 0
    this.cm = new CardManager({
      num: this.userNum
    })
    this.cardcheck = new CardTypeSize()
    this.user = new PokerUser({
      index: this.my
    })
  }
  initSocket() {
    const socket = io(this.wsUrl)
    socket.on('out', (cards) => {
      this.nowCard = cards
      this.history.push({
        who: this.nowUser,
        cards
      })
      this.next()
    })
    socket.on('start', (cards) => {
      let myCards = cards[this.my]
      const user = this.user
      user.cards = myCards
      user.on('confirm', (cards) => {
        try {
          if (this.check(cards)) {
            this.socket.emit('out', cards)
            user.out(cards)
          } else {
            this.context.$Message.error('不满足条件')
          }
        } catch (err) {
          this.context.$Message.error('错误')
        }
      })
      user.on('skip', () => {
        this.next()
      })
      user.on('win', () => {
        let otherUsers = this.users.filter((res) => res != user)
        user.win()
        otherUsers.forEach((res) => res.fail())
      })
      this.user = user
    })
    this.socket = socket
    this.start()
  }
  start() {
    let groups = this.cm.init()
    this.socket.emit('start', groups)
  }
  init() {
    this.nowCard = []
    this.initSocket()
    watch(
      () => {
        return this.my
      },
      (newValue, oldValue) => {
        store.set('pokerMy', newValue)
      }
    )
    // let groups = this.cm.init()
    // groups.forEach((res, index) => {
    //   const user = new PokerUser({
    //     cards: res,
    //     index: index
    //   })
    //   this.users.push(user)

    //   user.on('confirm', (cards) => {
    //     try {
    //       if (this.check(cards)) {
    //         user.out(cards)
    //         this.nowCard = cards
    //         this.history.push({
    //           who: user.index,
    //           cards
    //         })
    //         this.next()
    //       } else {
    //         this.context.$Message.error('不满足条件')
    //       }
    //     } catch (err) {
    //       this.context.$Message.error('错误')
    //     }
    //   })
    //   user.on('skip', () => {
    //     this.next()
    //   })
    //   user.on('win', () => {
    //     let otherUsers = this.users.filter((res) => res != user)
    //     user.win()
    //     otherUsers.forEach((res) => res.fail())
    //   })
    // })
  }
  next() {
    this.nowUser++
    this.nowUser = this.nowUser % this.userNum
  }
  check(cards) {
    let { nowCard } = this
    return this.cardcheck.compare(cards, nowCard)
  }
}

export class CardTypeSize {
  constructor() {
    this.TYPES = {
      T_SINGLE: 1,
      T_PAIR: 2,
      T_SAME3: 3,
      T_BOMB: 4,
      T_SAME32: 5,
      T_ORDER5MORE: 6,
      T_BIGPLANE: 7,
      T_PAIRPLANE: 8
    }
  }
  checkValid(cards) {
    let len = cards.length
    let flag = {
      type: 0,
      cards
    }
    const TYPES = this.TYPES
    const { T_SINGLE, T_PAIR, T_SAME3, T_BOMB, T_SAME32, T_ORDER5MORE, T_BIGPLANE, T_PAIRPLANE } = TYPES
    switch (len) {
      case 1:
        flag.type = T_SINGLE
        break
      case 2:
        if (this.isPair(cards)) {
          flag.type = T_PAIR
        }
        break
      case 3:
        if (this.isSame3(cards)) {
          flag.type = T_SAME3
        }
        break
      case 4:
        if (this.isBomb(cards)) {
          flag.type = T_BOMB
        }
        break
      case 5:
        if (this.isSame32(cards)) {
          flag.type = T_SAME32
        }
        if (this.isBomb(cards)) {
          flag.type = T_BOMB
        }
        if (this.isOrder5More(cards)) {
          flag.type = T_ORDER5MORE
        }
        break
      default:
        if (this.isOrder5More(cards)) {
          flag.type = T_ORDER5MORE
        } else if (this.isBomb(cards)) {
          flag.type = T_BOMB
        } else if (this.isBigPlane) {
          flag.type = T_BIGPLANE
        } else if (this.isPairPlane) {
          flag.type = T_PAIRPLANE
        }
        break
    }
    return flag
  }
  isPair(cards) {
    let len = cards.length
    if (len == 2 && cards[0].num == cards[1].num) {
      return true
    } else {
      return false
    }
  }
  isSame3(cards) {
    let len = cards.length
    if (len == 3) {
      return cards.every((res) => res.num == cards[0].num)
    }
  }
  isOrderMore(cards, limit) {
    if (cards.length >= limit) {
      let sortCards = sortBy(cards, 'num')
      let flag = true
      let hasA = sortCards.find((res) => res.num == 1)
      let prev
      if (hasA) {
        prev = sortCards[1]
        sortCards.shift()
      } else {
        prev = sortCards[0]
      }
      for (let i = 1; i < sortCards.length; i++) {
        if (sortCards[i].num - prev.num == 1) {
        } else {
          flag = false
        }
        prev = sortCards[i]
      }

      if (flag && hasA) {
        if (sortCards[sortCards.length - 1].num == 13 || sortCards[0].num == 2) {
        } else {
          flag = false
        }
      }
      return flag
    }
  }
  isOrder5More(cards) {
    return this.isOrderMore(cards, 5)
  }
  isSame32(cards) {
    let len = cards.length
    if (len == 5) {
      let [g1, g2] = values(groupBy(cards, 'num'))
      if ((g1.length == 3 && g2.length == 2) || (g1.length == 2 && g2.length == 3)) {
        let newCard = []
        if (g1.length > g2.length) {
          newCard = newCard.concat(g1, g2)
        } else {
          newCard = newCard.concat(g2, g1)
        }
        Object.assign(cards, newCard)
        return true
      }
    }
    return false
  }
  isBomb(cards) {
    let len = cards.length
    if (len >= 4) {
      let prev = cards[0]
      return cards.every((res) => res.num == prev.num)
    }
  }
  isPairPlane(cards) {
    let len = cards.length
    let flag = false
    if (len >= 6 && (len - 6) % 2 == 0) {
      let gs = groupBy(cards, (res) => res.num)
      let gs_value = values(gs)

      if (gs_value.every((res) => res.length == 2)) {
        let pickOne = gs_value.map((res) => {
          return res[0]
        })
        if (this.isOrderMore(pickOne, gs_value.length)) {
          flag = true
        }
      }
    }
    return flag
  }
  isBigPlane(cards) {
    let len = cards.length
    let flag = false
    if (len >= 9 && (len - 9) % 3 == 0) {
      let gs = groupBy(cards, (res) => res.num)
      let gs_value = values(gs)

      if (gs_value.every((res) => res.length == 3)) {
        let pickOne = gs_value.map((res) => {
          return res[0]
        })
        if (this.isOrderMore(pickOne, gs_value.length)) {
          flag = true
        }
      }
    }
    return flag
  }
  compare_single(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    return c1[0].size > c2[0].size
  }
  compare_pair(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    return c1[0].size > c2[0].size
  }
  compare_same3(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    return c1[0].size > c2[0].size
  }
  compare_order5more(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    if (c1.length == c2.length) {
      return c1[0].num > c2[0].num
    } else {
      return false
    }
  }
  compare_same32(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    let c1_3 = values(groupBy(c1, 'num')).find((res) => res.length == 3)[0].size
    let c2_3 = values(groupBy(c2, 'num')).find((res) => res.length == 3)[0].size
    return c1_3 > c2_3
  }
  compare_bomb(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    if (c1.length != c2.length) {
      return c1.length > c2.length
    } else {
      return c1[0].size > c2[0].size
    }
  }
  compare_bigplane(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    let c1_3 = values(groupBy(c1, 'num'))
    let c2_3 = values(groupBy(c2, 'num'))

    if (c1_3.length == c2_3.length) {
      return c1_3[0][0].num > c2_3[0][0].num
    } else {
      return false
    }
  }
  compare_pairplane(flag1, flag2) {
    const c1 = flag1.cards
    const c2 = flag2.cards
    let c1_3 = values(groupBy(c1, 'num'))
    let c2_3 = values(groupBy(c2, 'num'))

    if (c1_3.length == c2_3.length) {
      return c1_3[0][0].num > c2_3[0][0].num
    } else {
      return false
    }
  }
  compare(cards1, cards2) {
    const { T_SINGLE, T_PAIR, T_SAME3, T_BOMB, T_SAME32, T_ORDER5MORE, T_BIGPLANE } = this.TYPES
    const cardFlag1 = this.checkValid(cards1)
    if (!values(this.TYPES).includes(cardFlag1.type)) throw new Error('类型错误')
    if (cards2.length == 0) return true
    const cardFlag2 = this.checkValid(cards2)
    const type1 = cardFlag1.type
    const type2 = cardFlag2.type
    let isLarge = false
    if (type1 == type2) {
      switch (type1) {
        case T_SINGLE:
          isLarge = this.compare_single(cardFlag1, cardFlag2)
          break
        case T_PAIR:
          isLarge = this.compare_pair(cardFlag1, cardFlag2)
          break
        case T_SAME3:
          isLarge = this.compare_same3(cardFlag1, cardFlag2)
          break
        case T_SAME32:
          isLarge = this.compare_same32(cardFlag1, cardFlag2)
          break
        case T_ORDER5MORE:
          isLarge = this.compare_order5more(cardFlag1, cardFlag2)
          break
        case T_BOMB:
          isLarge = this.compare_bomb(cardFlag1, cardFlag2)
          break
        case T_BIGPLANE:
          isLarge = this.compare_bigplane(cardFlag1, cardFlag2)
          break
        case T_PAIRPLANE:
          isLarge = this.compare_pairplane(cardFlag1, cardFlag2)
        default:
          console.log(`其他的情况`)
          break
      }
    } else {
      if (type1 == T_BOMB) {
        isLarge = true
      }
    }
    return isLarge
  }
}
export class PokerUser extends EventEmitter {
  constructor(options = {}) {
    super()
    this.cards = options.cards || []
    this.index = options.index || 0
    this.history = []
  }
  //确认阶段
  confirm() {
    let cards = this.cards.filter((res) => res.selected)
    this.emit('confirm', cards)
  }
  select(card) {
    card.selected = !card.selected
  }
  win() {
    alert(`获胜了`)
  }
  fail() {
    alert('失败了')
  }
  skip() {
    this.emit('skip')
  }
  out(cards) {
    cards.forEach((card) => {
      let i = this.cards.findIndex((res) => res.key == card.key)
      this.cards.splice(i, 1)
    })
    if (this.cards.length == 0) {
      this.emit('win')
    }
  }
}

export class Card {
  constructor(options) {
    this.type = options.type || 0
    this.num = options.num || 0
    this.size = options.size || 0
    this.selected = false
    this.key = 0
  }
}
export class CardManager {
  constructor(options) {
    this.suitNum = 2
    this.divideNum = options.num
    this.suitList = []
  }
  static getCard(type, num = 0) {
    let size = 0
    if (num == 1) {
      size = 14
    } else if (num == 2) {
      size = 15
    } else {
      size = num
    }
    if (type == 4) {
      size = 17
      num = 100
    } else if (type == 5) {
      size = 16
      num = 99
    }
    // return new Card({
    //   type,
    //   num,
    //   size
    // })
    return {
      type,
      num,
      size
    }
  }
  getCard(type, num) {
    return CardManager.getCard(type, num)
  }
  init() {
    for (let s = 0; s < this.suitNum; s++) {
      for (let type = 0; type < 4; type++) {
        for (let i = 0; i < 13; i++) {
          const card = this.getCard(type, i + 1)
          this.suitList.push(card)
        }
      }
      const bigKingCard = this.getCard(4)
      const smallKingCard = this.getCard(5)
      this.suitList.push(bigKingCard)
      this.suitList.push(smallKingCard)
    }
    // console.log(this.suitList)
    return this.divide()
  }
  divide() {
    let { suitList, divideNum } = this
    let len = suitList.length
    let mod = len % divideNum
    let groupNum = Math.floor(len / divideNum)
    suitList = shuffle(suitList)
    suitList.forEach((res, index) => {
      res.key = 'i' + index
    })
    if (mod > 0) {
      suitList = suitList.slice(0, -1 * mod)
    }
    let groups = chunk(suitList, groupNum)
    let sortGroups = groups.map((res) => {
      return sortBy(res, ['size'])
    })
    return sortGroups
  }
}
